package com.panopset.io;

import static com.panopset.Util.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Vector;

/**
 * Process one or more files.
 *
 * @author Karl Dinwiddie
 */
public class FileProcessor {
    Vector<File>     files;
    Vector<Listener> listeners;
    boolean done = false;

    public void stop() {
        done = true;
    }

    public void exec() {
        if (files.isEmpty()) return;
        if (listeners.isEmpty()) return;
        String[] lines = new String[files.size()];
        FileReader[] fr = new FileReader[files.size()];
        BufferedReader[] br = new BufferedReader[files.size()];
        boolean[] rdrDone = new boolean[files.size()];

        for (int i=0; i<files.size(); i++) {
            rdrDone[i] = false;
            try {
                fr[i] = new FileReader(files.elementAt(i));
            } catch (FileNotFoundException e) {
                log(e);
                log(x("File not found") + COLON + SINGLE_SPACE +
                        getCanonicalPath(files.elementAt(i)));
                return;
            }
            br[i] = new BufferedReader(fr[i]);
        }

        while (!done) {
            boolean allDone = true;
            for (int i=0; i<files.size(); i++) {
                if (!rdrDone[i]) {
                    try {
                        lines[i] = br[i].readLine();
                        if (lines[i] == null) {
                            rdrDone[i] = true;
                        } else {
                            allDone = false;
                        }
                    } catch (IOException e) {
                        log(e);
                    }
                }
            }
            if (allDone) {
                done = true;
                for (Listener listener : listeners) {
                    listener.finish(this);
                }
            } else {
                for (Listener listener : listeners) {
                    listener.process(this, lines);
                }
            }
        }
    }


    private FileProcessor(Vector<File> files, Vector<Listener> listeners) {
        this.files = files;
        this.listeners =listeners;
    }

    public interface Listener {

        /**
         * Process a single line for each file.
         * @param processor
         * @param s If more than one file is being processed,
         * and element of s could be null.
         */
        void process(FileProcessor processor, String[] s);

        /**
         * This method is called after all the files have been processed.
         * @param processor
         */
        void finish(FileProcessor processor);

    }

    public static class Builder {
        Vector<File>     files     = new Vector<File>();
        Vector<Listener> listeners = new Vector<Listener>();

        /**
         * Add a File to the processor.
         *
         * @param file
         * @return Builder
         */
        public Builder file(File file) {
            files.add(file);
            return this;
        }

        /**
         * Add a Listener to the processor.
         * @param listener
         * @return Builder.
         */
        public Builder listener(Listener listener) {
            listeners.add(listener);
            return this;
        }

        /**
         *
         * @return FileProcessor
         */
        public FileProcessor construct() {
            return new FileProcessor(files,listeners);
        }
    }
}
